﻿using Dos.NGif;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Text;
using System.Web;
using System.Web.SessionState;

namespace Dos.Common
{
    public class Captcha : IHttpHandler, IRequiresSessionState
    {
        private Random randomNum = new Random((int)DateTime.Now.Ticks);

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        public Captcha()
        {
        }

        public string[] CaptchaGenerate()
        {
            byte num;
            Encoding encoding = Encoding.GetEncoding("gb2312");
            string[] strArrays = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
            string[] strArrays1 = new string[] { "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "T", "U", "V", "W", "X", "Y", "a", "b", "d", "e", "f", "g", "h", "i", "j", "k", "m", "n", "p", "q", "r", "t", "u", "v", "w", "x", "y" };
            string[] strArrays2 = new string[] { "あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ", "た", "ち", "つ", "て", "と", "な", "に", "ぬ", "ね", "の", "は", "ひ", "ふ", "ほ", "ま", "み", "む", "め", "も", "や", "ゆ", "よ", "ら", "り", "る", "れ", "ろ", "わ", "を", "ん", "ア", "イ", "ウ", "エ", "オ", "カ", "キ", "コ", "サ", "シ", "ス", "セ", "ソ", "タ", "チ", "ツ", "テ", "ト", "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "ヒ", "フ", "ホ", "マ", "ミ", "ム", "メ", "モ", "ヤ", "ユ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ワ", "ヲ", "ン", "が", "ぎ", "ぐ", "げ", "ご", "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "づ", "で", "ど", "ば", "び", "ぶ", "ぼ", "ぱ", "ぴ", "ぷ", "ぽ", "ガ", "ギ", "ゴ", "ザ", "ジ", "ズ", "ゼ", "ゾ", "ダ", "ヂ", "ヅ", "デ", "ド", "バ", "ビ", "ブ", "ボ", "パ", "ピ", "プ", "ポ" };
            string[] str = new string[CaptchaControl.captChaLength];
            for (int i = 0; i < CaptchaControl.captChaLength; i++)
            {
                switch (CaptchaControl.contentField)
                {
                    case CharacterContentField.DigitOnly:
                        {
                            int num1 = this.randomNum.Next(0, 10);
                            str[i] = num1.ToString();
                            break;
                        }
                    case CharacterContentField.LetterOnly:
                        {
                            str[i] = strArrays[this.randomNum.Next(0, (int)strArrays.Length)];
                            break;
                        }
                    case CharacterContentField.DigitAndLetter:
                        {
                            str[i] = strArrays1[this.randomNum.Next(0, (int)strArrays1.Length)];
                            break;
                        }
                    case CharacterContentField.CnCharOnly:
                        {
                            byte num2 = Convert.ToByte(this.randomNum.Next(176, 216));
                            num = (num2 == Convert.ToByte(215) ? Convert.ToByte(this.randomNum.Next(161, 250)) : Convert.ToByte(this.randomNum.Next(161, 255)));
                            str[i] = encoding.GetString(new byte[] { num2, num });
                            break;
                        }
                    case CharacterContentField.JpCharOnly:
                        {
                            str[i] = strArrays2[this.randomNum.Next(0, (int)strArrays2.Length)];
                            break;
                        }
                }
            }
            return str;
        }

        private Color ColorFromHsiToRgb(int h, int s, int i)
        {
            double num;
            double num1;
            double num2;
            double num3 = (double)h / 360;
            double num4 = (double)s / 100;
            double num5 = (double)i / 100;
            if (s != 0)
            {
                double num6 = num3 * 6;
                if (num6 == 6)
                {
                    num6 = 0;
                }
                int num7 = (int)num6;
                double num8 = num5 * (1 - num4);
                double num9 = num5 * (1 - num4 * (num6 - (double)num7));
                double num10 = num5 * (1 - num4 * (1 - (num6 - (double)num7)));
                switch (num7)
                {
                    case 0:
                        {
                            num = num5;
                            num1 = num10;
                            num2 = num8;
                            break;
                        }
                    case 1:
                        {
                            num = num9;
                            num1 = num5;
                            num2 = num8;
                            break;
                        }
                    case 2:
                        {
                            num = num8;
                            num1 = num5;
                            num2 = num10;
                            break;
                        }
                    case 3:
                        {
                            num = num8;
                            num1 = num9;
                            num2 = num5;
                            break;
                        }
                    case 4:
                        {
                            num = num10;
                            num1 = num8;
                            num2 = num5;
                            break;
                        }
                    default:
                        {
                            num = num5;
                            num1 = num8;
                            num2 = num9;
                            break;
                        }
                }
            }
            else
            {
                num = num5;
                num1 = num;
                num2 = num;
            }
            int num11 = Convert.ToInt32((double)(num * 255));
            int num12 = Convert.ToInt32((double)(num1 * 255));
            int num13 = Convert.ToInt32((double)(num2 * 255));
            return Color.FromArgb(num11, num12, num13);
        }

        public Bitmap CombineImageLayers(Bitmap backgroundImage, Bitmap foregroundImage)
        {
            Bitmap bitmap = new Bitmap(CaptchaControl.imageWidth, CaptchaControl.imageHeight);
            Graphics graphic = Graphics.FromImage(bitmap);
            graphic.DrawImage(backgroundImage, 0, 0);
            graphic.DrawImage(foregroundImage, 0, 0);
            return bitmap;
        }

        public Bitmap DistortImage(Bitmap sourceImage, double distortionRate, double initialPhase)
        {
            int num;
            Bitmap bitmap;
            Bitmap bitmap1 = new Bitmap(sourceImage.Width, sourceImage.Height);
            Graphics.FromImage(bitmap1);
            if (CaptchaControl.imageWidth < CaptchaControl.imageHeight)
            {
                for (int i = 0; i < sourceImage.Height; i++)
                {
                    for (int j = 0; j < sourceImage.Width; j++)
                    {
                        Color pixel = sourceImage.GetPixel(j, i);
                        num = (int)(distortionRate * Math.Sin((double)i / 10 + initialPhase)) + j;
                        if ((num < 0 ? false : num < sourceImage.Width))
                        {
                            bitmap1.SetPixel(num, i, pixel);
                        }
                    }
                }
                bitmap = bitmap1;
            }
            else
            {
                for (int k = 0; k < sourceImage.Width; k++)
                {
                    for (int l = 0; l < sourceImage.Height; l++)
                    {
                        Color color = sourceImage.GetPixel(k, l);
                        num = (int)(distortionRate * Math.Sin((double)k / 10 + initialPhase)) + l;
                        if ((num < 0 ? false : num < sourceImage.Height))
                        {
                            bitmap1.SetPixel(k, num, color);
                        }
                    }
                }
                bitmap = bitmap1;
            }
            return bitmap;
        }

        public Bitmap DrawBackgroundImage()
        {
            Pen pen;
            Bitmap bitmap;
            Bitmap bitmap1 = new Bitmap(CaptchaControl.imageWidth, CaptchaControl.imageHeight);
            Graphics graphic = Graphics.FromImage(bitmap1);
            graphic.Clear(CaptchaControl.backgroundColor);
            graphic.SmoothingMode = SmoothingMode.AntiAlias;
            if (CaptchaControl.noiseMode != NoisyRate.None)
            {
                int num = (int)Math.Sqrt((double)(CaptchaControl.imageWidth * CaptchaControl.imageHeight));
                for (int i = 0; i < num; i++)
                {
                    pen = new Pen(this.GetRandomColor(ColorSaturation.LowSaturation, this.randomNum.Next(50, 101)), 0f);
                    graphic.DrawRectangle(pen, this.randomNum.Next(CaptchaControl.imageWidth), this.randomNum.Next(CaptchaControl.imageHeight), 1, 1);
                }
                for (int j = 0; (double)j < Math.Sqrt((double)num); j++)
                {
                    pen = new Pen(this.GetRandomColor(ColorSaturation.LowSaturation, this.randomNum.Next(50, 101)), 0f);
                    graphic.DrawEllipse(pen, this.randomNum.Next(CaptchaControl.imageWidth), this.randomNum.Next(CaptchaControl.imageHeight), this.randomNum.Next(2, 5), this.randomNum.Next(2, 5));
                    graphic.DrawRectangle(pen, this.randomNum.Next(CaptchaControl.imageWidth), this.randomNum.Next(CaptchaControl.imageHeight), this.randomNum.Next(1, 5), this.randomNum.Next(1, 5));
                }
                if (CaptchaControl.noiseMode == NoisyRate.LowNoisy)
                {
                    bitmap = bitmap1;
                    return bitmap;
                }
                int num1 = this.randomNum.Next(2, 10);
                for (int k = 0; k < num1; k++)
                {
                    pen = new Pen(this.GetRandomColor(ColorSaturation.LowSaturation, this.randomNum.Next(50, 76)), 0f);
                    graphic.DrawLine(pen, this.randomNum.Next(bitmap1.Width), this.randomNum.Next(bitmap1.Height), this.randomNum.Next(bitmap1.Width), this.randomNum.Next(bitmap1.Height));
                }
            }
            bitmap = bitmap1;
            return bitmap;
        }

        public Bitmap DrawForegroundImage(string[] authCode)
        {
            PointF pointF;
            FontFamily fontFamily;
            FontFamily[] families = (new InstalledFontCollection()).Families;
            int num = 0;
            Brush solidBrush = null;
            Font font = null;
            Bitmap bitmap = new Bitmap(CaptchaControl.imageWidth, CaptchaControl.imageHeight);
            Graphics graphic = Graphics.FromImage(bitmap);
            int num1 = 0;
            int num2 = 0;
            Matrix transform = graphic.Transform;
            graphic.SmoothingMode = SmoothingMode.AntiAlias;
            graphic.TextRenderingHint = TextRenderingHint.AntiAlias;
            int num3 = 0;
            if (CaptchaControl.imageWidth < CaptchaControl.imageHeight)
            {
                num1 = CaptchaControl.imageHeight / CaptchaControl.captChaLength;
                num3 = ((double)CaptchaControl.imageWidth * 0.75 < (double)num1 ? (int)((double)CaptchaControl.imageWidth * 0.75) : num1);
            }
            else
            {
                num1 = CaptchaControl.imageWidth / CaptchaControl.captChaLength;
                num3 = ((double)CaptchaControl.imageHeight * 0.75 < (double)num1 ? (int)((double)CaptchaControl.imageHeight * 0.75) : num1);
            }
            int num4 = (int)((double)num3 * 0.6);
            num2 = num1 / 2;
            if (CaptchaControl.codeStringFillingMode == ColorMode.PureColor)
            {
                solidBrush = new SolidBrush(CaptchaControl.foregroundColor);
            }
            else if (CaptchaControl.codeStringFillingMode == ColorMode.GradientColor)
            {
                solidBrush = new LinearGradientBrush(new Rectangle(0, 0, CaptchaControl.imageWidth, CaptchaControl.imageHeight), this.GetRandomColor(ColorSaturation.HighSaturation, CaptchaControl.stringOpacity), this.GetRandomColor(ColorSaturation.HighSaturation, CaptchaControl.stringOpacity), (float)this.randomNum.Next(0, 360));
            }
            for (int i = 0; i < CaptchaControl.captChaLength; i++)
            {
                num = (CaptchaControl.codeFontSizeMode != FontSizeMode.SizeFixed ? this.randomNum.Next(num4, num3) : num3);
                if (CaptchaControl.codeFontMode == FontMode.FontLimited)
                {
                    font = ((CaptchaControl.fonts == null ? false : CaptchaControl.fonts.Count != 0) ? new Font(CaptchaControl.fonts[this.randomNum.Next(CaptchaControl.fonts.Count)].AuthCodeFont.Name, (float)num, FontStyle.Regular) : new Font(SystemFonts.DefaultFont.Name, (float)num, FontStyle.Regular));
                }
                else if (CaptchaControl.codeFontMode == FontMode.FontFree)
                {
                    do
                    {
                        fontFamily = families[this.randomNum.Next((int)families.Length)];
                    }
                    while (!fontFamily.IsStyleAvailable(FontStyle.Regular));
                    font = new Font(fontFamily.Name, (float)num, FontStyle.Regular);
                }
                int num5 = num / 5;
                if (CaptchaControl.codeStringFillingMode == ColorMode.RandomColor)
                {
                    solidBrush = new SolidBrush(this.GetRandomColor(ColorSaturation.HighSaturation, CaptchaControl.stringOpacity));
                }
                SizeF sizeF = graphic.MeasureString(authCode[i], font);
                pointF = (CaptchaControl.imageWidth < CaptchaControl.imageHeight ? new PointF((float)(CaptchaControl.imageWidth / 2), (float)(num2 + i * num1)) : new PointF((float)(num2 + i * num1), (float)(CaptchaControl.imageHeight / 2)));
                if (CaptchaControl.allowCharRotation)
                {
                    Matrix matrix = new Matrix();
                    matrix.RotateAt((float)this.randomNum.Next(-45, 45), pointF, MatrixOrder.Append);
                    graphic.Transform = matrix;
                }
                graphic.DrawString(authCode[i], font, solidBrush, (float)(pointF.X - sizeF.Width / 2f + (float)this.randomNum.Next(-num5, num5)), (float)(pointF.Y - sizeF.Height / 2f + (float)this.randomNum.Next(-num5, num5)));
                if (CaptchaControl.allowCharRotation)
                {
                    graphic.Transform = transform;
                }
            }
            if (CaptchaControl.noiseMode == NoisyRate.HighNoisy)
            {
                int num6 = this.randomNum.Next(2, 6);
                for (int j = 0; j < num6; j++)
                {
                    Pen pen = new Pen(this.GetRandomColor(ColorSaturation.NormalSaturation, this.randomNum.Next(50, 101)), (float)this.randomNum.Next(0, 3));
                    graphic.DrawLine(pen, this.randomNum.Next(bitmap.Width / 2), this.randomNum.Next(bitmap.Height), this.randomNum.Next(bitmap.Width / 2, bitmap.Width), this.randomNum.Next(bitmap.Height));
                }
            }
            return bitmap;
        }

        public string GenerateCaptchaImage(MemoryStream imageStream)
        {
            string str;
            string[] strArrays = this.CaptchaGenerate();
            Bitmap bitmap = this.DrawBackgroundImage();
            Bitmap bitmap1 = this.DrawForegroundImage(strArrays);
            string str1 = null;
            for (int i = 0; i < (int)strArrays.Length; i++)
            {
                str1 = string.Concat(str1, strArrays[i].Trim());
            }
            if ((CaptchaControl.isForegroundDynamic ? false : !CaptchaControl.isBackgroundDynamic))
            {
                if (CaptchaControl.allowDistortion)
                {
                    bitmap1 = this.DistortImage(bitmap1, 3, 0);
                }
                this.CombineImageLayers(bitmap, bitmap1).Save(imageStream, ImageFormat.Png);
                str = str1;
            }
            else
            {
                AnimatedGifEncoder animatedGifEncoder = new AnimatedGifEncoder();
                animatedGifEncoder.Start(imageStream);
                animatedGifEncoder.SetRepeat(0);
                if (!CaptchaControl.allowDistortion)
                {
                    animatedGifEncoder.SetDelay(800);
                    for (int j = 0; j < 5; j++)
                    {
                        if (CaptchaControl.isForegroundDynamic)
                        {
                            bitmap1 = this.DrawForegroundImage(strArrays);
                        }
                        if (CaptchaControl.isBackgroundDynamic)
                        {
                            bitmap = this.DrawBackgroundImage();
                        }
                        animatedGifEncoder.AddFrame(this.CombineImageLayers(bitmap, bitmap1));
                    }
                }
                else
                {
                    animatedGifEncoder.SetDelay(50);
                    Bitmap bitmap2 = this.DistortImage(bitmap1, 3, 3.14159265358979 * (double)this.randomNum.Next(0, 20) / 10);
                    for (int k = 0; k < 10; k++)
                    {
                        if (CaptchaControl.isForegroundDynamic)
                        {
                            bitmap2 = this.DistortImage(bitmap1, 3, 3.14159265358979 * (double)k / 5);
                        }
                        if (CaptchaControl.isBackgroundDynamic)
                        {
                            bitmap = this.DrawBackgroundImage();
                        }
                        animatedGifEncoder.AddFrame(this.CombineImageLayers(bitmap, bitmap2));
                    }
                }
                animatedGifEncoder.Finish();
                str = str1;
            }
            return str;
        }

        public void GenerateDesignTimeCaptchaImage(string imageSavingPath)
        {
            string[] strArrays = this.CaptchaGenerate();
            Bitmap bitmap = this.DrawBackgroundImage();
            Bitmap bitmap1 = this.DrawForegroundImage(strArrays);
            string str = null;
            for (int i = 0; i < (int)strArrays.Length; i++)
            {
                str = string.Concat(str, strArrays[i].Trim());
            }
            if (CaptchaControl.allowDistortion)
            {
                bitmap1 = this.DistortImage(bitmap1, 3, 0);
            }
            this.CombineImageLayers(bitmap, bitmap1).Save(imageSavingPath, ImageFormat.Png);
        }

        private Color GetRandomColor(ColorSaturation saturationMode, int opacity)
        {
            int num = 0;
            int num1 = 0;
            int num2 = this.randomNum.Next(0, 360);
            switch (saturationMode)
            {
                case ColorSaturation.HighSaturation:
                    {
                        num = this.randomNum.Next(80, 101);
                        num1 = this.randomNum.Next(0, 101);
                        break;
                    }
                case ColorSaturation.NormalSaturation:
                    {
                        num = this.randomNum.Next(40, 61);
                        num1 = this.randomNum.Next(30, 101);
                        break;
                    }
                case ColorSaturation.LowSaturation:
                    {
                        num = this.randomNum.Next(0, 31);
                        num1 = this.randomNum.Next(20, 101);
                        break;
                    }
            }
            Color color = Color.FromArgb((int)((double)opacity / 100 * 255), this.ColorFromHsiToRgb(num2, num, num1));
            return color;
        }

        public void ProcessRequest(HttpContext webContext)
        {
            MemoryStream memoryStream = new MemoryStream();
            string str = this.GenerateCaptchaImage(memoryStream);
            webContext.Session.Add(CaptchaControl.sessionName, str);
            webContext.Session.Add("Dos.Captcha.GenerateTime", DateTime.Now);
            webContext.Response.ClearContent();
            webContext.Response.ContentType = (CaptchaControl.isBackgroundDynamic || CaptchaControl.isForegroundDynamic ? "image/gif" : "image/png");
            webContext.Response.BinaryWrite(memoryStream.ToArray());
            memoryStream.Close();
            webContext.Response.End();
        }

        public void ProcessRequest()
        {
            this.ProcessRequest(HttpContext.Current);
        }
    }
}